//The MIT License
//
//Copyright (c) 2009 nodchip
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
package tv.dyndns.kishibe.client.game.input;

import java.util.logging.Level;
import java.util.logging.Logger;

import tv.dyndns.kishibe.client.Controller;
import tv.dyndns.kishibe.client.Service;
import tv.dyndns.kishibe.client.SharedData;
import tv.dyndns.kishibe.client.SoundPlayer;
import tv.dyndns.kishibe.client.UserData;
import tv.dyndns.kishibe.client.constant.Constant;
import tv.dyndns.kishibe.client.game.AnswerView;
import tv.dyndns.kishibe.client.game.SceneGame;
import tv.dyndns.kishibe.client.game.WidgetTimeProgressBar;
import tv.dyndns.kishibe.client.game.panel.QuestionPanel;
import tv.dyndns.kishibe.client.packet.PacketGameStatus;
import tv.dyndns.kishibe.client.packet.PacketProblem;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.VerticalPanel;

public abstract class InputWidget extends VerticalPanel {
	private static final Logger logger = Logger.getLogger(InputWidget.class.getName());
	private static final String[][] LETTERS = { { "1", "2", "3", "4", "5", "6", "7", "8" },
			{ "A", "B", "C", "D", "E", "F", "G", "H" } };
	protected static final String ANSWERED = "(解答済)";
	protected static final int DIGIT = 0;
	protected static final int ALPHA = 1;
	protected WidgetTimeProgressBar widgetTimeProgressBar;
	protected final PacketProblem problem;
	protected final AnswerView answerView;
	private final QuestionPanel questionPanel;
	private long startTime;

	protected InputWidget(PacketProblem problem, AnswerView answerView, QuestionPanel questionPanel) {
		this.problem = Preconditions.checkNotNull(problem);
		this.answerView = Preconditions.checkNotNull(answerView);
		this.questionPanel = Preconditions.checkNotNull(questionPanel);
		setVerticalAlignment(ALIGN_TOP);
		setHorizontalAlignment(ALIGN_CENTER);
	}

	public abstract void enable(boolean b);

	/**
	 * プレイヤーの解答を非表示にする。このクラスを継承したクラスはこのメソッドをオーバーライドすることで、回答非表示の動作を変更することができる。
	 */
	protected void hideAnswer() {
		answerView.set(ANSWERED, false);
	}

	/**
	 * ゲーム状態を受け取る
	 * 
	 * @param gameStatus
	 *            ゲーム状態
	 */
	public void onReceivedGameStatus(PacketGameStatus gameStatus) {
	}

	protected void sendAnswer(final String answer) {
		playSound(Constant.SOUND_URL_BUTTON_OK);
		enable(false);

		if (questionPanel != null) {
			questionPanel.showCorrectRatio();
		}

		int sessionId = SharedData.get().getSessionId();
		int playerListId = SharedData.get().getPlayerListIndex();
		int responseTime = (int) (System.currentTimeMillis() - startTime);
		if (responseTime < 30 * 1000 + 1000) {
			Service.Util.getInstance().sendAnswer(sessionId, playerListId, answer,
					UserData.get().getUserCode(), responseTime, callbackSendAnswer);
		} else {
			String message = "時間制限を超えた解答が送信されました: "
					+ Objects.toStringHelper(this)
							.add("sessionId", SharedData.get().getSessionId())
							.add("playerListIndex", SharedData.get().getPlayerListIndex())
							.add("userCode", UserData.get().getUserCode())
							.add("remoteAddress", SharedData.get().getRemoteAddress()).toString();
			logger.log(Level.WARNING, message);
		}

		if (UserData.get().isHideAnswer()) {
			hideAnswer();
		}
	}

	private final AsyncCallback<Void> callbackSendAnswer = new AsyncCallback<Void>() {
		public void onSuccess(Void result) {
			SceneGame scene = (SceneGame) Controller.getInstance().getScene();
			scene.onSendAnswer();
		}

		public void onFailure(Throwable caught) {
			logger.log(Level.WARNING, "解答の送信中にエラーが発生しました", caught);
		}
	};

	protected void playSound(String url) {
		SoundPlayer.getInstance().play(url);
	}

	public String getAnswerMark(String answer) {
		return answer;
	}

	public String getChoiceMark(String choice) {
		return choice;
	}

	protected String getLetter(int letterType, int letterIndex) {
		return LETTERS[letterType][letterIndex];
	}

	/**
	 * %nによる改行が含まれる文字列をSafeHtmlに変換する
	 * 
	 * @param s
	 *            文字列.
	 * @return {@link SafeHtml}.
	 */
	protected static SafeHtml toMultilineSafeHtml(String s) {
		return new SafeHtmlBuilder().appendEscapedLines(s.replaceAll("%n", "\n")).toSafeHtml();
	}

	@Override
	protected void onLoad() {
		super.onLoad();
		startTime = System.currentTimeMillis();
	}
}
